library(knitr)
library(tidyr)
library(dplyr)
library(ggplot2)
library(plotly)
library(caret)
library(tibble)
library(ggpubr)

Raport wykonany w ramach kursu Zaawansowana eksploracja danych, na semestrze zimowym 2024/2025.

Executive summary

Problem

Raport służy do analizy bazy danych materiałów wykorzystywanych w tworzeniu baterii.

Źródło danych

Wykorzystane dane pochodzą z inicjatywy naukowej Departamentu Energii USA Materials Project. Pobrane zostały ze strony kursu dnia 24.11.2024.

Opis danych

Zbiór danych składa się z następujących kolumn:

  • Battery ID - identyfikator baterii.
  • Battery Formula - wzór chemiczny materiału baterii.
  • Working Ion - główny jon, który odpowiada za transport ładunku w baterii.
  • Formula Charge - wzór chemiczny materiału baterii w stanie naładowanym.
  • Formula Discharge - wzór chemiczny materiału baterii w stanie rozładowanym.
  • Max Delta Volume - zmiana objętości w % dla danego kroku napięcia za pomocą wzoru: max(charge, discharge)/min(charge, discharge) -1.
  • Average Voltage - średnie napięcie dla poszczególnego kroku napięcia.
  • Gravimetric Capacity - pojemność grawimetryczna, czyli ilość energii na jednostkę masy (mAh/g).
  • Volumetric Capacity - pojemność wolumetryczna, czyli ilość energii na jednostkę objętości (mAh/cm³).
  • Gravimetric Energy - gęstość energii w odniesieniu do masy baterii (Wh/kg).
  • Volumetric Energy - gęstość energii w odniesieniu do objętości baterii (Wh/L).
  • Atomic Fraction Charge - udział atomowy składników w stanie naładowanym.
  • Atomic Fraction Discharge - udział atomowy składników w stanie rozładowanym.
  • Stability Charge - wskaźnik stabilności materiału w stanie naładowanym.
  • Stability Discharge - wskaźnik stabilności materiału w stanie rozładowanym.
  • Steps - liczba odrębnych kroków napięcia od pełnego naładowania do rozładowania, oparta na stabilnych stanach pośrednich.
  • Max Voltage Step - maksymalna bezwzględna różnica między sąsiednimi krokami napięcia.

Czyszczenie danych

Dane były przetworzone i wyczyszczone przez autorów ale upewniamy się że nie bedzie danych brakujących.

df <- read.csv("data/mp_batteries.csv", header = T)
df <- df[complete.cases(df),]

Podstawowe statystyki

Wyświetlenie wszystkich zmiennych oraz podstawowych statystyk. Dla wartości tekstowych zwrócone zostały: liczba unikalnych wartości i najczęstsza wartość.

kable(head(df[1:5]))
Battery.ID Battery.Formula Working.Ion Formula.Charge Formula.Discharge
mp-30_Al Al0-2Cu Al Cu Al2Cu
mp-1022721_Al Al1-3Cu Al AlCu Al3Cu
mp-8637_Al Al0-5Mo Al Mo Al5Mo
mp-129_Al Al0-12Mo Al Mo Al12Mo
mp-91_Al Al0-12W Al W Al12W
mp-1055908_Al Al0-12Mn Al Mn MnAl12
summary_fun <- function(x){
  mt <- table(x)
  c(n_distinct(x), names(mt)[which.max(mt)])
}
sdf <- mapply(summary_fun, df[1:5])
rownames(sdf) <- c('Liczba unikalnych','Najczęstsza wartość')
kable(sdf)
Battery.ID Battery.Formula Working.Ion Formula.Charge Formula.Discharge
Liczba unikalnych 4351 3301 10 2096 3173
Najczęstsza wartość mp-1001925_Mg Li0-1V2OF5 Li MnO2 LiCoPO4
kable(head(df[6:11]))
Max.Delta.Volume Average.Voltage Gravimetric.Capacity Volumetric.Capacity Gravimetric.Energy Volumetric.Energy
3.043399 0.0890331 1368.481 5562.790 121.84009 495.27253
1.243653 -0.0215863 1112.937 4418.980 -24.02423 -95.38962
4.762574 0.1227568 1741.504 7175.702 213.78156 880.86651
12.723893 0.0431214 2298.811 7346.232 99.12801 316.78006
12.494598 0.0292342 1900.745 7332.719 55.56677 214.36621
18.236156 0.0397314 2547.693 7592.916 101.22330 301.67688
kable(summary(df[6:11]))
Max.Delta.Volume Average.Voltage Gravimetric.Capacity Volumetric.Capacity Gravimetric.Energy Volumetric.Energy
Min. : 0.00002 Min. :-7.755 Min. : 5.176 Min. : 24.08 Min. :-583.5 Min. :-2208.1
1st Qu.: 0.01747 1st Qu.: 2.226 1st Qu.: 88.108 1st Qu.: 311.62 1st Qu.: 211.7 1st Qu.: 821.6
Median : 0.04203 Median : 3.301 Median : 130.691 Median : 507.03 Median : 401.8 Median : 1463.8
Mean : 0.37531 Mean : 3.083 Mean : 158.291 Mean : 610.62 Mean : 444.1 Mean : 1664.0
3rd Qu.: 0.08595 3rd Qu.: 4.019 3rd Qu.: 187.600 3rd Qu.: 722.75 3rd Qu.: 614.4 3rd Qu.: 2252.3
Max. :293.19322 Max. :54.569 Max. :2557.627 Max. :7619.19 Max. :5926.9 Max. :18305.9
kable(head(df[12:17]))
Atomic.Fraction.Charge Atomic.Fraction.Discharge Stability.Charge Stability.Discharge Steps Max.Voltage.Step
0.0 0.6666667 0.0000000 0.0000000 1 0
0.5 0.7500000 0.0740612 0.0962458 1 0
0.0 0.8333333 0.4114601 0.0452120 1 0
0.0 0.9230769 0.0000000 0.0114456 1 0
0.0 0.9230769 0.0000000 0.0000000 1 0
0.0 0.9230769 0.1454643 0.0000000 1 0
kable(summary(df[12:17]))
Atomic.Fraction.Charge Atomic.Fraction.Discharge Stability.Charge Stability.Discharge Steps Max.Voltage.Step
Min. :0.00000 Min. :0.007407 Min. :0.00000 Min. :0.00000 Min. :1.000 Min. : 0.0000
1st Qu.:0.00000 1st Qu.:0.086957 1st Qu.:0.03301 1st Qu.:0.01952 1st Qu.:1.000 1st Qu.: 0.0000
Median :0.00000 Median :0.142857 Median :0.07319 Median :0.04878 Median :1.000 Median : 0.0000
Mean :0.03986 Mean :0.159077 Mean :0.14257 Mean :0.12207 Mean :1.167 Mean : 0.1503
3rd Qu.:0.04762 3rd Qu.:0.200000 3rd Qu.:0.13160 3rd Qu.:0.09299 3rd Qu.:1.000 3rd Qu.: 0.0000
Max. :0.90909 Max. :0.993333 Max. :6.48710 Max. :6.27781 Max. :6.000 Max. :26.9607

Wartości odstające

Na podstawie podstawowych statystyk można stwierdzić, że istnieją wartości odstające (np. Gravimetric.Capacity, Volumetric.Capacity) oraz że część wartości została wprowadzona lub zmierzona niepoprawnie (Average.Voltage) Wartości odstające zostaną usunięte przy użyciu z-score.

z_threshold <- 3
outliers_threshold <- df %>% 
  select_if(is.numeric) %>% 
  summarise(across(everything(), list(
    "odcięcie dolne" = ~ -z_threshold * sd(.x) + mean(.x),
    "odcięcie górne" = ~ z_threshold * sd(.x) + mean(.x)
  ))) %>%
  pivot_longer(
    cols = everything(),
    names_to = c("column_name",".value"),
    names_pattern = "(.*)_(.*)"
  )
outliers_threshold <- outliers_threshold %>%
  column_to_rownames(var='column_name')

outliers_count <- df %>%
  select_if(is.numeric) %>% 
  summarise(across(everything(), 
            list(
              outliers_count = ~ sum(abs(scale(.x)) > z_threshold))
  )) %>%
  pivot_longer(
    cols = everything(),
    names_to = "column_name",
    values_to = "liczba odciętych"
  )

outliers_count <- outliers_count %>%
  column_to_rownames(var='column_name')

cbind(outliers_threshold, outliers_count) %>% knitr::kable()
odcięcie dolne odcięcie górne liczba odciętych
Max.Delta.Volume -20.1801987 20.9308261 4
Average.Voltage -2.3830258 8.5493113 18
Gravimetric.Capacity -336.4500340 653.0318129 43
Volumetric.Capacity -1080.9352788 2302.1834762 62
Gravimetric.Energy -609.0380088 1497.2507692 40
Volumetric.Energy -2229.3472896 5557.4441170 39
Atomic.Fraction.Charge -0.2258255 0.3055370 81
Atomic.Fraction.Discharge -0.2020458 0.5202002 94
Stability.Charge -0.9922662 1.2773994 52
Stability.Discharge -0.9348829 1.1790262 73
Steps -0.2241607 2.5583368 99
Max.Voltage.Step -1.7399143 2.0404938 66
count_before <- nrow(df)
df <- df %>% filter(if_all(where(~ is.numeric(.)), ~ abs(scale(.)) < z_threshold))
count_after <- nrow(df)

Dla najlepszej jakości danych wybrano próg 3, przed wyczyszczeniem liczba wierszy wynosiła: 4351, a po 3935.

Analiza

Poniżej przedstawiono rozkład poszczególnych wartości oraz relacji między wybranymi parami atrybutów.

Rozkłady parametrów

p <- ggplot(df, aes(x = `Working.Ion`)) +
    geom_bar(fill = "blue", color = "black") + 
    labs(x='główny jon', y='Liczność', title='Rozkład parametru główny jon')

ggplotly(p)
present_variable <- function(data, column, binwidth, columnName) {
p <- ggplot(data, aes(x=column)) +
    geom_histogram( binwidth=binwidth) + 
    labs(x=columnName, y='Liczność', title=paste('Rozkład parametru', columnName))
  
ggplotly(p)
}
present_variable(df, df$"Max.Delta.Volume", binwidth = 0.01, 'maksymalna zmiana objętości')
present_variable(df, df$"Average.Voltage", binwidth = 0.2, 'średnie napięcie')
present_variable(df, df$"Gravimetric.Capacity", binwidth = 10, 'pojemność grawimetryczna')
present_variable(df, df$"Volumetric.Capacity", binwidth = 40, 'pojemność wolumetryczna')
present_variable(df, df$"Gravimetric.Energy", binwidth = 40, 'gęstość energii w odniesieniu do masy baterii')
present_variable(df, df$"Volumetric.Energy", binwidth = 120, 'gęstość energii w odniesieniu do objętości baterii')
present_variable(df, df$"Atomic.Fraction.Charge", binwidth = 0.01, 'udział atomowy składników w stanie naładowanym')
present_variable(df, df$"Atomic.Fraction.Discharge", binwidth = 0.01, 'udział atomowy składników w stanie rozładowanym')
present_variable(df, df$"Stability.Charge", binwidth = 0.01, 'wskaźnik stabilności materiału w stanie naładowanym')
present_variable(df, df$"Stability.Discharge", binwidth = 0.01, 'wskaźnik stabilności materiału w stanie rozładowanym')
present_variable(df, df$"Steps", binwidth = 0.5, 'liczba odrębnych kroków napięcia od pełnego naładowania do rozładowania')
present_variable(df, df$"Max.Voltage.Step", binwidth = 1, 'maksymalna bezwzględna różnica między sąsiednimi krokami napięcia')